# coding=UTF-8
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.sites.models import Site
from django.conf import settings
from django.db import models
import os, stat #FIXME: Debería importarlo únicamente donde los uso?

class Color(models.Model):
    """
    The available colors.
    """
    name = models.CharField(_(u'Color'), max_length=150)
    rgb = models.CharField(_(u'Representación en RGB'), max_length=6, unique=True)
    image = models.ImageField(_(u'Imagen'), upload_to='tshirts/', blank=True)

    def __unicode__(self):
        return _(u'%(nombre)s (#%(rgb)s)') % { 'nombre': self.name, 'rgb': self.rgb }

    class Meta:
        ordering = ['name']
        verbose_name = _(u'Color')
        verbose_name_plural = _(u'Colores')

    class Admin:
        pass

class Category(models.Model):
    """
    A product type, this would be "t-shirt", "cd" or any category.
    """
    name = models.CharField(_(u'Nombre'), max_length=50)
    slug = models.SlugField(_(u'Slug'), prepopulate_from=('name',), unique=True)
    icon = models.ImageField(_(u'Icono'), upload_to='icons/', blank=True)
    parent = models.ForeignKey('self', verbose_name=_(u'Categoría padre'), related_name='childs', blank=True, null=True)

    def __unicode__(self):
        return self.name

    def is_child(self):
        return not (self.parent == None)

    class Meta:
        ordering = ['name']
        verbose_name = _(u'Categoría')
        verbose_name_plural = _(u'Categorías')

    class Admin:
        pass

class Product(models.Model):
    """
    The product itself.
    """
    name = models.CharField(_(u'Nombre'), max_length=100) # Debe ser único dentro de su categoría.
    slug = models.SlugField(_(u'Slug'), prepopulate_from=('name',), unique=True)
    comment = models.CharField(_('Comentario conciso'), max_length=255)
    description = models.TextField(_(u'Descripción'))
    category = models.ForeignKey(Category, verbose_name=_(u'Categoría'), related_name='product_set')
    price = models.DecimalField(_(u'Precio'), max_digits=6, decimal_places=2)
    weight = models.PositiveIntegerField(_(u'Peso (gr)'))
    ctime = models.DateTimeField(auto_now_add=True)
    related_items = models.ManyToManyField('self', verbose_name=_(u'Productos similares'), related_name='related_items_set', blank=True)
    also_purchased = models.ManyToManyField('self', verbose_name=_(u'Compras relacionadas'), related_name='also_purchased_set', blank=True)
    stock = models.PositiveIntegerField(_(u'Stock'), blank=True, null=True)
    site = models.ForeignKey(Site, verbose_name=_(u'Sitio'), related_name='product_set', blank=True, null=True)
    #TODO: Implement http://django-tagging.googlecode.com/
    # stock = generic.GenericRelation(InStock)

    def __unicode__(self):
        return self.name

    def get_price(self):
        if self.price % 1 == 0:
            return int(self.price)
        return self.price

    def get_slug(self):
        return self.slug

    def get_main_image(self):
        if not self.count_images():
            return None
        try:
            image = self.image_set.get(main=True)
        except:
            image = self.image_set.all()[:1][0]
        return image

    def get_comment(self):
        return self.comment

    def get_categories(self, top_category=None, categories=None):
        if top_category == None:
            top_category = self.category
        if categories == None:
            categories = []
        categories.insert(0, top_category)
        if top_category.is_child():
            self.get_categories(top_category.parent, categories)
        return categories

    def get_main_category(self):
        return self.category

    def get_description(self):
        return self.description

    def has_size(self):
        return self.is_tshirt()

    def get_sizes(self):
        if not self.is_tshirt():
            return None
        sizes = []
        for tshirt in self.tshirt_set.all():
            if tshirt.size not in sizes:
                sizes.append(tshirt.size)
        return sizes

    def get_genders(self):
        if not self.is_tshirt():
            return None
        genders = []
        for tshirt in self.tshirt_set.all():
            if tshirt.gender == 'M':
                if 'M' not in genders:
                    genders.append('M')
            if tshirt.gender == 'F':
                if 'F' not in genders:
                    genders.append('F')
        return genders

    def get_stock(self):
        if self.is_tshirt():
            stock = 0
            for tshirt in self.tshirt_set.all():
                stock += tshirt.stock
            return stock
        return self.stock

    def get_colors(self):
        colors = []
        for tshirt in self.tshirt_set.all():
            if tshirt.color not in colors:
                colors.append(tshirt.color)

        return colors

    def get_similar(self, how_many=2):
        #FIXME: Los productos similares actualmente se manejan con una
        # auto-relación del producto a través de un ManyToManyField. Esto va a
        # cambiar, se van a implementar tags, por lo que los similares se van a
        # obtener en base a las tags bajo las cuales cada uno está identificado.
        similar = []
        for item in self.related_items.all()[:how_many]:
            if item.has_images():
                similar.append(item)
        return similar

    def get_parent_comments(self):
        pass

    def has_colors(self):
        if not self.is_tshirt():
            return False
        for product in self.tshirt_set.all():
            pass

    def has_similar(self):
        return self.related_items.count()

    def has_many_similar(self, how_many=2):
        return (self.related_items.count() > how_many)

    def has_action_shots(self):
        return self.action_shots.count()

    def has_many_action_shots(self, how_many=2):
        return (self.action_shots.count() > how_many)

    def count_images(self):
        return self.image_set.count()

    def is_tshirt(self):
        """
        Returns True if there are any relations between self and TShirt.
        """
        if self.tshirt_set.count():
            return True
        return False

    def has_images(self):
        return (self.image_set.count() > 0)

    def main_image(self):
        main = None
        try:
            main = self.image_set.get(main=True)
        except:
            if self.image_set.count() > 0:
                main = self.image_set.all()[:1][0]
        return main

    def is_favourite(self):
        try:
            from django.contrib.contenttypes.models import ContentType
            from superalikal.middleware import threadlocals
            from djopping_favs.models import FavouriteItem
        except ImportError, e:
            print e
            return False

        try:
            current_user = threadlocals.get_current_user()
        except Exception, e:
            print e
        try:
            ctype = ContentType.objects.get_for_model(self)
            favourite = FavouriteItem.objects.get(
                content_type=ctype,
                object_id=self.id,
                user=current_user)
        except Exception, e:
            print e
            return False
        return True

    class Meta:
        ordering = ['name']
        unique_together = ('slug', 'category')
        verbose_name = _(u'Producto')
        verbose_name_plural = _(u'Productos')

    class Admin:
        pass

# En Product guardo el modelo de la remera, es decir, la remera estampada, le
# asigno su imagen y todo.
# Ahora, en TShirt guardo la relación entre una remera lisa (materia prima) por
# ej, una remera blanca, talle L, y el modelo de la remera. Una vez que entra
# una remera de un nuevo color, la agrego en Color, e ingreso acá para cada
# talle nuevo un stock.
# ¡Está bien que product sea un ManyToManyField!
class TShirt(models.Model):
    """
    A T-Shirt object. It includes extra information such as the color and the
    size. Despite extending Product it also has a 'stock' attribute. It's
    expected not to have stock in the Product object, but it could happen when
    there's stock of a particular t-shirt.
    """
    from choices import SIZE_CHOICES, GENDER_CHOICES

    product = models.ManyToManyField(Product, verbose_name=_(u'Producto'), related_name='tshirt_set')
    color = models.ForeignKey(Color, verbose_name=_(u'Color'), related_name='tshirts')
    size = models.CharField(_(u'Tamaño'), max_length=3, choices=SIZE_CHOICES)
    gender = models.CharField(_(u'Modelo'), max_length=1, choices=GENDER_CHOICES)
    stock = models.PositiveIntegerField(_(u'Stock'))

    def __unicode__(self):
        return _(u'%(size)s, %(color)s') % { 'color': self.color, 'size': self.size }

    class Meta:
        verbose_name = _(u'Remera')
        verbose_name_plural = _(u'Remeras')

    class Admin:
        pass

class ProductImage(models.Model):
    """
    The images of a product.
    """
    from choices import ANGLE_CHOICES

    product = models.ForeignKey(Product, verbose_name=_(u'Producto'), related_name='image_set') # max_width=230px
    image = models.ImageField(_(u'Imagen'), upload_to='products/')
    #TODO: Cambiar nombre de este atributo.
    angle = models.CharField(_(u'Foto tomada desde'), max_length=1, choices=ANGLE_CHOICES)
    main = models.BooleanField(_(u'Imagen principal'))
    width = models.PositiveIntegerField(_(u'Ancho'), blank=True, null=True)
    height = models.PositiveIntegerField(_(u'Altura'), blank=True, null=True)

    def __unicode__(self):
        return settings.MEDIA_URL + self.image

    def save(self):
        # from PythonMagick import Image
        from DjoppingMagick import Image

        filename, max_width = str(self.get_image_filename()), settings.MAX_WIDTH
        image_file = Image(filename)
        if image_file.size().width() > max_width:
            image_file.scale(str(max_width))
            image_file.write(filename)
        self.width, self.height = image_file.size().width(), image_file.size().height()
        super(ProductImage, self).save()

    def delete(self):
        for file in self.get_thumbnails(self.get_image_filename().split('/')[-1:][0]):
            os.remove(file)
        super(ProductImage, self).delete()

    def get_thumbnails(self, filename, dirname=None):
        if dirname == None:
            dirname = settings.THUMBS_ROOT
        content = os.listdir(dirname)
        for file in content:
            try:
                st = os.lstat(os.path.join(dirname, file))
            except:
                continue
            if stat.S_ISDIR(st.st_mode):
                for found_file in self.get_thumbnails(filename, os.path.join(dirname, file)):
                    yield found_file
            else:
                if file == filename:
                    yield os.path.join(dirname, file)

    class Meta:
        # ordering = ['product']
        unique_together = ('product', 'main')
        verbose_name = _(u'Imagen de Producto')
        verbose_name_plural = _(u'Imágenes de Producto')

    class Admin:
        pass

class ActionShot(models.Model):
    """
    Pictures of happy customers using our happy products.
    """
    product = models.ForeignKey(Product, verbose_name=_(u'Producto'), related_name='action_shots')
    shot = models.ImageField(_(u'Foto del producto'), upload_to='action_shots/', unique=True)
    comment = models.CharField(_(u'Comentario'), max_length=255)

    def __unicode__(self):
        return self.get_shot_url()

    class Meta:
        ordering = ['product']
        verbose_name = _(u'Producto en acción')
        verbose_name_plural = _(u'Productos en acción')

class Detail(models.Model):
    """
    Possible detail specification for every product.
    """
    from choices import DETAIL_TYPE_CHOICES

    name = models.CharField(_(u'Detalle'), max_length=255, unique=True)
    type = models.CharField(_(u'Tipo de Dato'), max_length=4, choices=DETAIL_TYPE_CHOICES)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name']
        verbose_name = _(u'Detalle')
        verbose_name_plural = _(u'Detalles')

    class Admin:
        pass

#FIXME: Especificaciones. Quizás deba llamarse ProductSpecification.
class ProductDetail(models.Model):
    """
    Details associated to a product.
    """
    product = models.ForeignKey(Product, verbose_name=_(u'Producto'), related_name='detail_set')
    name = models.ForeignKey(Detail, verbose_name=_(u'Detalle'), related_name='associated_products')
    value = models.CharField(_(u'Valor'), max_length=255)

    def __unicode__(self):
        return self.detail_name

    class Meta:
        ordering = ['product']
        unique_together = ('product', 'name')
        verbose_name = _(u'Detalle de Producto')
        verbose_name_plural = _(u'Detalles de Producto')

    class Admin:
        pass

class ProductViews(models.Model):
    """
    Times a product has been seen.
    """
    product = models.ForeignKey(Product, verbose_name=_(u'Producto'), related_name='view_set')
    timestamp = models.DateTimeField(_(u'Fecha y hora'), auto_now_add=True)

    class Meta:
        ordering = ['-timestamp']
        verbose_name = _(u'Vista a un Producto')
        verbose_name_plural = _(u'Vistas a un Producto')

"""
# Realmente necesito esto?
class ProductSpecification(models.Model): # Deprecated!
    \"""
    A product and it's different attributes is a specification. For one product you can have multiple "configurations", different colors, sizes and/or materials.
    \"""
    from choices import SIZE_CHOICES

    product = models.ForeignKey(Product, verbose_name=_(u'Producto'), related_name='specification')
    color = models.ForeignKey(Color, verbose_name=_(u'Color'), related_name='products', blank=True)
    size = models.CharField(_(u'Tamaño'), max_length=3, choices=SIZE_CHOICES, blank=True)
    price = models.DecimalField(_(u'Precio'), blank=True, null=True)
    # stock = generic.GenericRelation(InStock)

    #TODO: def save() para chequear que no exista ya el mismo product en stock.
    #def save(self):
    #    pass

class InStock(models.Model): # Deprecated!
    \"""
    The stock of a product. It could be a number of stocked items or zero, when there's stock but it's undefined how much.
    \"""
    product = models.ForeignKey(Product, verbose_name=_(u'Producto'), related_name='stock')
    stock = models.PositiveIntegerField(_(u'Stock'), blank=True, null=True)

class ProductPrice(models.Model):
    \"""
    The price of a product.
    \"""
    # Aca va un producto, una especificación, una relación genérica o que mierda???
    product = models.ForeignKey(Product, verbose_name=_(u'Producto'), related_name='prices')
    price = models.FloatField(_(u'Precio'))

"""
